#ifndef THREADPOOL
#define THREADPOOL

#include <list>
#include <cstdio>
#include <iostream>
#include <exception>

#include <pthread.h>

#include "Locker.hpp"

/**
 * 2023-07-03
 * 实现线程池类
 * 定义为模板类，方便复用到各种不同的任务上
 */
template <typename MyRequest>
class MyThreadPool {
private:
    int thread_number = 0; // 线程的数量
    pthread_t *thread_arr = nullptr; // 储存线程的数组

    int request_max_number = 0; // 请求队列中，最多的允许等待的任务数量
    std::list<MyRequest*> request_queue = std::list<MyRequest*>(); // 请求队列，存储需要处理的任务

    MyMutex mutex = MyMutex(); // 互斥锁
    MySemaphore semaphore = MySemaphore(); // 信号量，用来判断是否有任务需要处理

    bool stop_flag = false; // 是否需要结束某一个线程的标志量

    // 线程池中，每个线程的工作函数
    static void* worker(void *arg) {
        MyThreadPool *thread_pool = (MyThreadPool*)arg;
        thread_pool->run();
        return (void*)thread_pool;
    }

public:
    // 构造函数，初始化线程池，根据给定的线程数量和最大的请求数量
    MyThreadPool(int thread_number = 10, int request_max_number = 1000) {
        // 处理参数不合法的情况// 处理参数不合法的情况
        if (thread_number <= 0 || request_max_number <= 0) {
            std::cerr << "Invalid Parameter!" << std::endl;
            throw std::exception();
        }
        
        // 初始化参数
        this->thread_number = thread_number;
        this->request_max_number = request_max_number;
        this->thread_arr = new pthread_t[this->thread_number];

        // 处理数组申请失败的情况
        if (this->thread_arr == nullptr) {
            std::cerr << "Init New Threads Failed!" << std::endl;
            throw std::exception();
        }

        // 创建并分离每一个线程，并进行异常处理
        for (int i = 0; i < this->thread_number; ++i) {
            std::cout << "Creating Threads " << i + 1 << "/" << this->thread_number << std::endl;

            // 创建线程，传递进去的工作函数需要是一个静态函数，为了让工作函数能访问类内的成员变量，可以将this指针传递进去
            int res_create =  pthread_create(&this->thread_arr[i], nullptr, this->worker, this);
            if (res_create != 0) {
                std::cerr << "Create Thread Fail, return non-zero value: " << res_create << std::endl;
                perror("Create Thread Fail, "); // 处理创建线程失败的情况
                delete[] this->thread_arr;
                throw std::exception();
            }

            // 分离线程，为了资源回收
            int res_detach = pthread_detach(this->thread_arr[i]);
            if (res_detach != 0) {
                std::cerr << "Detaching Thread Fail, return non-zero value: " << res_detach << std::endl;
                perror("Detach Thread Fail, "); // 处理分离线程失败的情况
                delete[] this->thread_arr;
                throw std::exception();
            }

        }
    }

    // 析构函数，释放所有资源
    ~MyThreadPool() {
        this->stop_flag = true;
        delete[] this->thread_arr;
    }

    // 添加一个任务到请求队列
    bool add_request(MyRequest *request) {
        this->mutex.lock(); // 先上锁

        // 如果已经达到了大请求数量，就不添加任务
        if ((int)this->request_queue.size() > this->request_max_number) {
            this->mutex.unlock(); // 上完的锁要解开
            return false;
        }

        this->request_queue.emplace_back(request); // 添加任务
        this->mutex.unlock(); // 解锁
        this->semaphore.post(); // 添加请求后，增加信号量

        return true;
    }

    // 线程池运行函数
    void run() {
        // 在停止以前，不断循环
        while (!this->stop_flag) {
            this->semaphore.wait(); // 首先，等待信号量
            this->mutex.lock(); // 如果等待到了数据，先上锁

            // 检查一下，是不是真的有请求，如果没有，重新解锁互斥锁然后继续等待
            if (this->request_queue.empty()) {
                this->mutex.unlock();
                continue;
            }

            // 取一个任务
            MyRequest *request = this->request_queue.front();
            this->request_queue.pop_front();

            // 获取完任务后，就可以解锁了
            this->mutex.unlock();

            // 再次对任务进行一下检查
            if (request == nullptr) continue;

            // 执行任务，要求任务类需要有process方法
            request->process();
        }
    }
};

#endif
